/******************************************************************************* * Copyright (c) 2010, 2011 Obeo. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.docs.intent.exporter.services; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Path; import org.eclipse.emf.codegen.ecore.genmodel.GenModel; import org.eclipse.emf.common.EMFPlugin; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory; import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory; import org.eclipse.mylyn.docs.intent.client.ui.logger.IntentUiLogger; import org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter; import org.eclipse.mylyn.docs.intent.core.compiler.TraceabilityIndex; import org.eclipse.mylyn.docs.intent.core.compiler.TraceabilityIndexEntry; import org.eclipse.mylyn.docs.intent.markup.gen.services.ImageServices; /** * Utility class allowing to determine the images associated to some EObject, and copy them inside the * exported documentation. * * @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a> */ public final class CopyImageUtils { /** * The {@link AdapterFactoryItemDelegator} to use to get images from {@link EObject}s. */ private static AdapterFactoryItemDelegator itemDelegator; /** * The resource set to use. */ private static ResourceSetImpl resourceSet; /** * Private constructor. */ private CopyImageUtils() { } /** * Determines the image associated to the given EObject and copies it inside the exported documentation. * * @param any * the eobject to get the image from * @param repositoryAdapter * the repository adapter to use to access to informations (traceability index...) * @param outputFolder * the target folder in which image will be copied * @return the image associated to the given EObject */ public static String copyImageAndGetImageID(EObject any, RepositoryAdapter repositoryAdapter, File outputFolder) { String qualifiedImageID = ""; // Step 1: getting the image URL thanks to the item delegator Object imageURL = getImageURL(any); if (imageURL instanceof URL) { try { // Step 2: resolve URL URL resolvedURL = FileLocator.resolve((URL)imageURL); EClassifier classifier = null; if (any instanceof EClassifier) { classifier = (EClassifier)any; } else { classifier = any.eClass(); } // If default "Item" image has been if (resolvedURL.toString().contains("org.eclipse.emf.edit") && resolvedURL.toString().endsWith("/icons/full/obj16/Item.gif")) { // we search for an "edit" plugin in the workspace imageURL = getImageFromWorkspace(classifier, repositoryAdapter); if (imageURL != null) { resolvedURL = (URL)imageURL; } } // Step 3: copy image in the exported documentation if (resolvedURL != null && resolvedURL.getFile() != null && outputFolder != null) { qualifiedImageID = copyImageIfNeeded(classifier, outputFolder, resolvedURL, resolvedURL.openStream()); } } catch (IOException e) { IntentUiLogger.logError(e); } } return qualifiedImageID; } /** * Searches for an edit plugin corresponding to the given EObject and tries to retrieve its associated * image. * * @param repositoryAdapter * the repository adapter to use to access to informations (traceability index...) * @param any * the eobject to get the image from * @return the URL of the image corresponding to the given EObject, null if none found */ private static URL getImageFromWorkspace(EClassifier any, RepositoryAdapter repositoryAdapter) { // If the core.resource plugin is not available, we return null if (EMFPlugin.IS_RESOURCES_BUNDLE_AVAILABLE) { TraceabilityIndex projectTraceabilityIndex = IntentAcceleoServices .getTraceabilityIndex(repositoryAdapter); if (projectTraceabilityIndex != null) { for (TraceabilityIndexEntry entry : projectTraceabilityIndex.getEntries()) { if (any.eResource().getURI().toString().contains(entry.getGeneratedResourcePath())) { URI metamodelURI = entry.getResourceDeclaration().getUri(); doGetImageFromWorkspace(metamodelURI, any); } } } } return null; } /** * Searches for an edit plugin corresponding to the given EObject and tries to retrieve its associated * image. * * @param metamodelURI * the {@link URI} * @param classifier * the {@link EObject} to get the image from * @return the URL of the image associated to the given classifier (if any found) */ private static URL doGetImageFromWorkspace(URI metamodelURI, EClassifier classifier) { URL imageURL = null; if (metamodelURI != null && metamodelURI.toString().replace("\"", "").endsWith("ecore")) { URI genModelURI = URI.createURI(metamodelURI.toString().replace("\"", "") .replace("ecore", "genmodel")); try { Resource resource = getResourceSet().getResource(genModelURI, true); if (resource.getContents().isEmpty() || !(resource.getContents().iterator().next() instanceof GenModel)) { return null; } String editIconsDirectory = ((GenModel)resource.getContents().iterator().next()) .getEditIconsDirectory(); IFolder folder = ResourcesPlugin.getWorkspace().getRoot() .getFolder(new Path(editIconsDirectory + "/full/obj16")); if (folder.exists()) { for (String imageExtension : new String[] {"gif", "png", }) { if (folder.getFile(classifier.getName() + "." + imageExtension).exists()) { imageURL = new URL("file:/" + folder.getFile(classifier.getName() + "." + imageExtension) .getLocation().toString()); } } } // CHECKSTYLE:OFF } catch (RuntimeException e) { // CHECKSTYLE:ON IntentUiLogger.logInfo("Cannot find genmodel at " + genModelURI + ". Default image will be use to display " + classifier.getName()); } catch (MalformedURLException e) { IntentUiLogger.logError(e); } } return imageURL; } /** * Returns the URL of the image associated to the given {@link EObject} through AdapterFactories. * * @param any * the element to get the image from * @return the URL of the image associated to the given {@link EObject} */ private static Object getImageURL(EObject any) { Object imageURL = null; // Step 1: getting the image URL thanks to the item delegator if (any instanceof EClass && ((EClassifier)any).getEPackage() != null) { EObject instance = ((EClassifier)any).getEPackage().getEFactoryInstance().create((EClass)any); imageURL = getItemDelegator(any).getImage(instance); } else { imageURL = getItemDelegator(any).getImage(any); } // Step 2: convert image location into URL format if needed if (!(imageURL instanceof URL)) { if (imageURL instanceof URI) { try { imageURL = new URL(imageURL.toString()); } catch (MalformedURLException e) { // silent catch } } else { if (imageURL instanceof org.eclipse.emf.edit.provider.ComposedImage) { imageURL = ((org.eclipse.emf.edit.provider.ComposedImage)imageURL).getImages().iterator() .next(); } } } return imageURL; } /** * Copies the image associated to the given classifier (and with the given URL) into the given output * folder. * * @param classifier * the type associated to the image * @param outputFolder * the output folder in which the image will be copied * @param imageURL * the URL of the image to copy * @param sourceStream * an input stream on the image * @return the path where the image was copied * @throws IOException * if files cannot be properly accessed */ private static String copyImageIfNeeded(EClassifier classifier, File outputFolder, URL imageURL, InputStream sourceStream) throws IOException { String packageName = ""; if (classifier.getEPackage() != null) { packageName = classifier.getEPackage().getName(); } File targetFile = new File(outputFolder.getAbsolutePath() + "/icons/generated/" + packageName + imageURL.getFile().substring(imageURL.getFile().lastIndexOf('/'))); // create folders if needed : new File(outputFolder.getAbsolutePath() + "/icons/generated/" + packageName).mkdirs(); if (!targetFile.exists()) { ImageServices.copyFile(sourceStream, targetFile); } String copiedImagePath = targetFile.getAbsolutePath().toString(); String outputFolderPath = outputFolder.getAbsolutePath(); return "../" + copiedImagePath.substring(outputFolderPath.length()); } /** * Returns the {@link AdapterFactoryItemDelegator} to use for getting images associated to the given * EObject. * * @param any * the EObject the EObject to get the image from * @return the {@link AdapterFactoryItemDelegator} to use for getting images associated to the given * EObject */ private static AdapterFactoryItemDelegator getItemDelegator(EObject any) { if (itemDelegator == null) { ComposedAdapterFactory adapterFactory = new ComposedAdapterFactory( ComposedAdapterFactory.Descriptor.Registry.INSTANCE); adapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory()); adapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory()); itemDelegator = new AdapterFactoryItemDelegator(adapterFactory); } return itemDelegator; } /** * Returns the Resource set to use. * * @return the resource set to use */ private static ResourceSet getResourceSet() { if (resourceSet == null) { resourceSet = new ResourceSetImpl(); } return resourceSet; } /** * Disposes the service. */ public static void dispose() { if (itemDelegator != null) { ((ComposedAdapterFactory)itemDelegator.getAdapterFactory()).dispose(); } resourceSet = null; itemDelegator = null; } }